home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / make5.cq / MAKE.C
Text File  |  1985-06-03  |  25KB  |  831 lines

  1. /*
  2.   This a  called 'Make' and is a much simplified version of
  3.   the make utility on UNIX (a trademark or something of AT&T)
  4.   written  using the Lattice C compile
  5.   for the  IBM Personal Computer.  The Lattice package is
  6.   available from Lifeboat Assoc. 1651 Third Avenue
  7.   New York, NY 10128 .
  8.  
  9.   'Make'  takes a  file of  dependencies (a  'makefile') and
  10.   decides  what commands have to be executed to bring the  files
  11.   up to date.  These commands are  either  executed  directly from
  12.   'Make'  or written to the standard output without executing
  13.   them.
  14.  
  15. 'Makefile' format:
  16.   - There  must be  a 'makefile'; you can't  take input from  the
  17.   standard input.
  18.   - The default name of the 'makefile' is  'MAKEFILE'  on the
  19.   default  disk.  Different 'makefiles' can be specified using
  20.   the '-f' option  on the  command  line.  If the '-f' option is
  21.   used, the default 'makefile' is  not processed.
  22.   - Any blank lines in the 'makefile(s)'  are ignored.
  23.   - A line in a 'makefile' that starts with a tab  character is
  24.   a 'howto' line  and consists of  a command name followed  by
  25.   arguments.  The  command  name must be a file name,  e.g.
  26.   'cc'.  When  commands are executed,  the PATH  environment
  27.   variable is used to find the command, in (hopefully) the
  28.   same manner as  DOS does. 'Howto'  lines apply to the most
  29.   recently preceding 'dependency'  line.  It is an  error for
  30.   a 'howto' line  to precede the first 'dependency' line.
  31.   - Any other non-blank line is a  'dependency' line.  'Dependency'
  32.   lines consist of a filename followed by  a (possibly empty) list
  33.   of dependent filenames.
  34.  
  35. Operation:
  36.   Syntax:
  37.     make [filename]  [-f makefilename] [-i] [-n]
  38.   -i means continue even  if an error is encountered while
  39.     executing a command.
  40.   -n means don't  execute  the commands, just write  the ones that
  41.     should be executed to  the standard output.  This is useful
  42.     for creating batch files, for  example.
  43.   -f specifies that the following  argument is the  name of  a makefile
  44.     to be  used instead of  the default (MAKEFILE).
  45.   All arguments may be repeated and relative position of  the
  46.   arguments is not important.  If  multiple definitions of  a file
  47.   are found, only  the first one is significant.
  48.  
  49.   First,  'Make' reads all  of the  makefiles.  It then proceeds through
  50.   all of  the filename arguments,  'making'  each one in turn.  A file
  51.   is remade if it  is out  of date  with respect to  the files it depends
  52.   on or is non-existent.  Dependencies are processed in a  'tree' fashion,
  53.   so that  the lowest-order files  are remade first.
  54.  
  55.   'Make'  cannot execute DOS built-in commands e.g. 'cd' or 'dir'.
  56.   'Make'  uses the  first 20k or so  after the resident portion of DOS.
  57.   all definitions and howto's are stored in dynamically allocated struct's.
  58.  Any executed commands are loaded above 'Make'  in memory.
  59.  
  60.   'Make'  REQUIRES  DOS 2.0  (or higher?).
  61.  
  62.  
  63.   The code is a little kludgy in  places.
  64.  
  65.   No guarantees or warranties of  any kind:  I think it works and
  66.   I use it.
  67.  
  68.   Any suggestions  for improvements gratefully accepted.
  69.  
  70.   I believe that  commercial versions exist.  I also beleive that  they
  71.   would be superior to this.
  72.  
  73. version 2.0 comments:
  74.   This program was converted to Lattice 'C' ver 2.11 on 15 jun 84.
  75.   This allowed the use of the lattice 'fork' command. The command
  76.   will automatically search the path name specified to find the
  77.   desired executable image. This also allows the use of image names
  78.   with out the extension. ie 'lc1' instead of 'lc1.exe'. All of
  79.   the assembler routines have been replaced with lattice dos calls.
  80.  
  81.   The Lattice version uses about 55k bytes less memory than the
  82.   Desmet version. This is nice for the systems with already tight
  83.   memory requirements.
  84. version 3 comments:
  85.   The default makefile name is MAKEFILE not MAKEFILE.DAT.
  86.   There now is a symbol processor to do substitiutions
  87.     in the argument line.
  88.   A symbol definition MUST begin with a $.
  89.   An example follows.
  90.   Fixed a bug-If a dependent file did not exist then make didn't
  91.     work correctly.
  92.   Checks to see if a command results in a non-zero return code.
  93.     If so then aborts unless the -i flag is used.
  94.  
  95.   Any comments on this code should be directed to
  96.   Jeffrey Spidle
  97.   Systems Analyst
  98.   Office of Continuing Education
  99.   Iowa State University
  100.   Ames, IA 50011
  101.   or a message on one of the following BBS.
  102.   Gene Plantz (312)887-4227
  103.   Lynn Long (918)749-0718
  104.   Bob Blackwell (319)363-3314
  105.  
  106.  
  107. */
  108.  
  109.  
  110. /*
  111. Written  by John  M Sellens, April, 1984
  112. Modified for Lattice C ver 2.11 by Jeff Spidle jun 15 84
  113.  
  114. Code is  all original except where indicated otherwise.
  115.  
  116. Until August, 1984:
  117.   jmsellens@watrose.UUCP
  118.  
  119.   107 - 180 Brybeck Cres.
  120.   Kitchener, Ontario
  121.   N2M 5G4
  122.  
  123. After August, 1984:
  124.   c/o 1135 Lansdowne Ave.  SW
  125.   Calgary, Alberta
  126.   T2S 1A4
  127.  
  128. (c) Copyright 1984 John  M Sellens
  129. Permission is granted to use, distribute and/or  modify this code unless
  130. done for direct  commercial profit.  If you find  these routines useful,
  131. modest contributions (monetary or otherwise) will be gratefully  accepted.
  132. Author's name, address and this  notice must be included  in any copies.
  133.  
  134. <TAB> = ASCII 09
  135. An example: To compile this program the following makefile was used
  136. $CFLAGS -ms -i/code/c/lc/
  137. make.exe make.obj
  138. <TAB>link /code/c/lc/s/cs+make,make,make,/code/c/lc/s/lcs -map
  139. make.obj make.c /code/c/lc/stdio.h
  140. <TAB>lc1 make $CFLAGS -i/code/c/lc/s/ -n
  141. <TAB>lc2 make
  142.  
  143.    An explination: make.exe is a dependent file. Is is dependent on
  144.    make.obj. make.obj is dependent on make.c and stdio.h. If the
  145.    following command is issued:MAKE make.exe then make will
  146.    check to see if either make.c or stdio.h has a newer date&time
  147.    than make.obj. if so then the 2 compile instructions are issued.
  148.    then the link instruction will be issued. If only make.obj is
  149.    newer than make.exe then only the link step would be executed.
  150.  
  151. The symbol substitution will end up having the lc1 call look like
  152.   lc1 make -ms -i/code/c/lc/ -i/code/c/lc/s/ -n
  153.  
  154. Hints: Dependencies can be in any order. Make will resolve them
  155.        correctly.
  156.  
  157.        How to lines must begin with a <TAB> not just 7 spaces.
  158.  
  159.        Symbol definition lines must start with a $.
  160.  
  161.        Symbols cannot have other symbols in their definition.
  162.  
  163.        A symbol may have a max of 39 characters.
  164.  
  165.        The equate for a symbol may be up to 80 characters.
  166.  
  167.        You may have an unlimited(within reason) number of
  168.        symbols.
  169.  
  170.        A symbol that is not defined will be copied to the
  171.        output line. ie
  172.        lc2 $TEST
  173.        with $TEST not defined will create the command
  174.        lc2 $TEST
  175.  
  176.        Symbols are case specific. upper and lower case are significant.
  177.  
  178.        The command line must specify what file you wish to
  179.        make. You may have more than one set of file definitions
  180.        in a makefile. If you do  you may run out of memory. I
  181.        haven't run into this yet but I suppose it is possible.
  182.  
  183.        If a command returns an error-code (ERRORLEVEL) not equal
  184.        to zero then MAKE thinks that there was an error. MAKE
  185.        will abort processing unless the -i (ignore errors) flag
  186.        is used.
  187.  
  188. Any suggestions or improvements will be much appreciated. I
  189. am next going to try to put definable symbols for substitution
  190. in a makefile next aka UNIX-MAKE. So we will see what happens.
  191. */
  192.  
  193.  
  194. #include <stdio.h>
  195. #include <dos.h>
  196. #include <ctype.h>
  197.  
  198. #define  TRUE 1
  199. #define  FALSE 0
  200. #define  DEFAULT  "MAKEFILE"
  201. #define  INMAX  255    /* maximum input line length  */
  202. extern  char *getmem() ;
  203. extern int _oserr, errno ;
  204.  
  205.  
  206. struct sym_ptr
  207.   {
  208.   struct sym_str *data ;
  209.   struct sym_ptr *next ;
  210.   } ;
  211.  
  212. struct sym_str
  213.   {
  214.   char symbol[40] ; /* max symbol size in lattice c is 39 chars */
  215.   char equals[81] ; /* so we had to default to something */
  216.   } ;
  217.  
  218. /* declare some global variables for the symbols */
  219. struct sym_ptr list ;
  220. struct sym_ptr *current ; /* pointer to the current symbol */
  221.                           /* thus we know where to add more to */
  222.  
  223. struct howrec {
  224.   char *howcom,*howargs;
  225.   struct  howrec *nexthow;
  226. };
  227.  
  228. struct deprec {
  229.   char *name;
  230.   struct  defnrec  *def;
  231.   struct  deprec *nextdep;
  232. };
  233.  
  234. struct defnrec {
  235.   char *name;
  236.   int uptodate;
  237.   long modified;
  238.   struct  deprec *dependson;
  239.   struct  howrec *howto;
  240.   struct  defnrec  *nextdefn;
  241. };
  242.  
  243. struct dorec {
  244.   char *name;
  245.   struct  dorec *nextdo;
  246. };
  247.  
  248. struct defnrec *defnlist;
  249. struct dorec *dolist;
  250.  
  251. int execute;
  252. int stopOnErr;
  253. int madesomething;
  254. int knowhow;
  255.  
  256. main(argc,argv)
  257. int argc;
  258. char *argv[];
  259. {
  260.   long make();
  261.   long void ;
  262.   current = &list ;
  263.   current->next = NULL ;
  264.   current->data = NULL ;
  265.   init(argc,argv);
  266.  
  267.   /* now  fall down the dolist and  do them  all */
  268.   while (dolist != NULL)  {
  269.     madesomething  =  FALSE;
  270.     void = make(dolist->name);    /* ignore return value */
  271.     if (!madesomething) {
  272.       if (knowhow)
  273.         fprintf(stderr,"Make: '%s' is up to  date\n",dolist->name);
  274.       else  {
  275.         fprintf(stderr,"Make: Don't  know how to  make '%s'\n",
  276.           dolist->name);
  277.         if (stopOnErr)
  278.           exit(-1);
  279.       }
  280.     }
  281.     dolist = dolist->nextdo;
  282.   }
  283. }
  284.  
  285. init(argc,argv)
  286. int argc;
  287. char *argv[];
  288. {
  289.   int i,  usedefault;
  290.   dolist  = NULL;
  291.   defnlist = NULL;
  292.   usedefault = TRUE;
  293.   execute  = TRUE;
  294.   stopOnErr = TRUE;
  295.  
  296.   for (i=1; i < argc; i++) {
  297.     if (argv[i][0] == '-') {  /* option */
  298.       switch (argv[i][1]) {
  299.         case 'f': case 'F':  /* arg following is a makefile */
  300.           if  (++i  < argc)  {
  301.             readmakefile(argv[i]);
  302.             usedefault = FALSE;
  303.           } else {
  304.             fprintf(stderr,"Make: '-f' requires filename\n");
  305.             exit(-1);
  306.           }
  307.           break;
  308.         case 'i': case 'I':  /* ignore errors on execution */
  309.           stopOnErr = FALSE;
  310.           break;
  311.         case 'n': case 'N':  /* don't execute commands - just print */
  312.           execute  = FALSE;
  313.           break;
  314.         default:
  315.           fprintf(stderr,"Make: unknown option '%s'\n",argv[i]);
  316.       }
  317.     } else {  /* it must be something  to make  */
  318.       add_do(argv[i]);
  319.     }
  320.   }
  321.   if (usedefault)
  322.     readmakefile(DEFAULT);
  323.  
  324. }
  325.  
  326. long make(s)  /*  returns  the modified  date/time */
  327. char *s;
  328. {
  329.   struct  defnrec  *defnp;
  330.   struct  deprec *depp;
  331.   struct  howrec *howp;
  332.   char    exp_args[128] ;
  333.   char    system_call[255] ;
  334.   long latest, getmodified(), lmax(), currtime();
  335.   int void, return_code ;
  336.  
  337.   /* look  for the  definition */
  338.   defnp =  defnlist;
  339.   while (defnp !=  NULL) {
  340.     if (strcmp(defnp->name,s) == 0)
  341.       break;
  342.     defnp  =  defnp->nextdefn;
  343.   }
  344.  
  345.   if (defnp == NULL) {  /* don't know how  to make  it */
  346.     knowhow  = FALSE;
  347.     latest = getmodified(s);
  348.     if (latest==0) {  /* doesn't exist but  don't know  how to make */
  349.       fprintf(stderr,"Make: Can't make '%s'\n",s);
  350.       exit(-1);
  351.     } else  /* exists - assume it's  up to date since we don't know  */
  352.       return(latest);
  353.   }
  354.  
  355.   if (defnp->uptodate)
  356.     return(defnp->modified);
  357.  
  358.   /* now  make sure everything that it depends on  is up to  date */
  359.   latest  = 0;
  360.   depp =  defnp->dependson;
  361.   while (depp !=  NULL) {
  362.     latest = lmax(make(depp->name),latest);
  363.     depp = depp->nextdep;
  364.   }
  365.  
  366.   knowhow  = TRUE;  /* has  dependencies therefore we know how */
  367.  
  368.   /* if necessary, execute all of  the commands to  make it  */
  369.   /* if (out of date) ||  (depends  on nothing)    */
  370.   if (latest > defnp->modified ||  defnp->dependson==NULL)  {
  371.     /* make  those  suckers  */
  372.     howp = defnp->howto;
  373.     while  (howp != NULL) {
  374.       expand_args(howp->howargs, exp_args) ;
  375.       printf("%s %s\n",howp->howcom,exp_args);
  376.       if (execute)
  377.         {
  378.         void = forklp(howp->howcom,exp_args,NULL) ;
  379.         if (void == 0) /* success loading function */
  380.           {
  381.           /* now do a wait to see if the function returns an ok code */
  382.           return_code = wait() ;
  383.           if (return_code != 0) /* error code returned */
  384.             {
  385.             printf("MAKE: error returned from %s %s, code = %d\n",
  386.                    howp->howcom, exp_args, return_code ) ;
  387.             if  (stopOnErr)
  388.               exit(-1);
  389.             } /* endif return_code != 0 */
  390.           }
  391.         else
  392.           { /* fork had an error loading */
  393.           if (_oserr == 2) /* error for file not found */
  394.             { /* lets do a system call instead then */
  395.             strcpy( system_call, howp->howcom ) ;
  396.             strcat( system_call, " " ) ;
  397.             strcat( system_call, exp_args ) ;
  398.             void = system( system_call ) ;
  399.             if (void != 0) /* error in system call */
  400.               {
  401.               printf("MAKE: system call error from %s %s, code = %d\n",
  402.                      howp->howcom, exp_args, _oserr ) ;
  403.               if  (stopOnErr)
  404.                 exit(-1);
  405.               } /* endif id void != 0 */
  406.             }
  407.           else
  408.             {
  409.             printf("\nMake: error on '%s %s' _oserr = %d\n",
  410.                 howp->howcom,exp_args, _oserr);
  411.             if  (stopOnErr)
  412.               exit(-1);
  413.             } /* endif _oserr == 2 */
  414.           } /* endif void == 0 */
  415.         } /* endif execute */
  416.       howp  = howp->nexthow;
  417.     } /* end while */
  418.     defnp->modified  = currtime();
  419.     defnp->uptodate  = TRUE;
  420.     if (defnp->howto != NULL)  /* we had instructions */
  421.       madesomething =  TRUE;
  422.   }
  423.  
  424.   return(defnp->modified);
  425.  
  426. }
  427.  
  428. expand_args( in, out )
  429. char *in, *out ;
  430.   {
  431.   char *posin, *posout, *possym ;
  432.   char symbol[40] ;
  433.   char *get_symval(), *symval ;
  434.  
  435.   posin = in ;
  436.   posout = out ;
  437.   while (TRUE)
  438.     {
  439.     while ( (*posin != '$') && (*posin != '\0') )
  440.       *posout++ = *posin++ ; /* copy till we find a $ */
  441.  
  442.     if (*posin == '\0') /* have reached the end of the input */
  443.       {                 /* so exit */
  444.       *posout = '\0' ;  /* terminate the output string first tho */
  445.       return ;
  446.       }
  447.  
  448.     possym = symbol ;   /* point symbol pointer at the begining */
  449.     /* skip over the $ so we can test for alphanumeric */
  450.     *possym++ = *posin++ ; /* copy's the $ */
  451.     while ( isalnum(*posin) )
  452.       *possym++ = *posin++ ; /* copy in the suspected symbol */
  453.     *possym = '\0' ; /* zero terminate it */
  454.     /* get the value of the found symbol */
  455.     if ( (symval = get_symval( symbol )) == NULL )
  456.       { /* do this if there isn't a symbol match */
  457.       possym = symbol ; /* reset the symbol position */
  458.       /* copy the symbol to the output */
  459.       while (*possym != '\0' )
  460.         *posout++ = *possym++ ;
  461.       }
  462.     else /* do this if there is one */
  463.       {
  464.       /* copy the symbol equate to the output */
  465.       while (*symval != 0)
  466.         *posout++ = *symval++ ;
  467.       }
  468.     }
  469.     /* should never get to here */
  470.   return ;
  471.   }
  472.  
  473. char *get_symval( symbol )
  474. char *symbol;
  475.   {
  476.   struct sym_ptr *cur_ptr ;
  477.  
  478.   cur_ptr = &list ;             /* start at the begining of the list */
  479.   while (cur_ptr->data != NULL) /* while there is data */
  480.     {
  481.     if (strcmp(cur_ptr->data->symbol, symbol) == 0) /* they match */
  482.       {
  483.       return(cur_ptr->data->equals) ; /* return the pointer to */
  484.                                       /* the equate string */
  485.       }
  486.     else /* they dont */
  487.       cur_ptr = cur_ptr->next ; /* point cur_ptr to the next symbol */
  488.     }
  489.   return(NULL) ;
  490.   }
  491.  
  492. add_do(s)
  493. char *s;
  494. {
  495.   struct  dorec *ptr1, *ptr2;
  496.   char *get_mem();
  497.  
  498.   ptr1 =  (struct  dorec *)get_mem(sizeof(struct dorec));
  499.  
  500.   ptr1->name = s;  /* okay  since only called with  an argv  */
  501.   ptr1->nextdo =  NULL;
  502.  
  503.   uppercase(ptr1->name);
  504.  
  505.   /* now  go down  the dolist */
  506.   if (dolist == NULL)
  507.     dolist = ptr1;
  508.   else {
  509.     ptr2 = dolist;
  510.     while  (ptr2->nextdo != NULL)
  511.       ptr2  = ptr2->nextdo;
  512.     ptr2->nextdo = ptr1;
  513.   }
  514.  
  515. }
  516.  
  517.  
  518. readmakefile(s)
  519. char *s;
  520. {
  521.   int doneline, pos, i, j;
  522.   long getmodified() ;
  523.   FILE *fil ;
  524.   char inline[INMAX], info[INMAX];
  525.   char *get_mem();
  526.   struct  defnrec  *defnp,  *defnp2;
  527.   struct  deprec *depp, *depp2;
  528.   struct  howrec *howp, *howp2;
  529.  
  530.   if ( (fil = fopen(s,"r")) == NULL)
  531.     {
  532.     fprintf(stderr,"Make:  Couldn't open '%s'\n",s);
  533.     return;
  534.     }
  535.  
  536.   while (fgets(inline,INMAX,fil)  != NULL)
  537.     {
  538.     inline[strlen(inline)-1] = '\0';  /* strip trailing newline */
  539.  
  540.     if (inline[0]  == '\0')  /* ignore blank  lines */
  541.       continue;
  542.  
  543.     switch (inline[0])
  544.       {
  545.       default:
  546.         uppercase(inline);
  547.  
  548.         /* get what we're defining into  info  */
  549.         if (sscanf(inline,"%s ",info) != 1)
  550.           {
  551.           fprintf(stderr,"Make: Can't  scan: '%s'\n",inline);
  552.           continue;
  553.           }
  554.         /* get a new  struct */
  555.         defnp =  (struct  defnrec  *)get_mem(sizeof(struct  defnrec));
  556.         /* add it to  the end  of  defnlist */
  557.         if (defnlist  ==  NULL)
  558.           defnlist = defnp;
  559.         else
  560.           {
  561.           defnp2 = defnlist;
  562.           while (defnp2->nextdefn  != NULL)
  563.             defnp2 = defnp2->nextdefn;
  564.           defnp2->nextdefn = defnp;
  565.           }
  566.         /* initialize it */
  567.         defnp->name = get_mem(strlen(info)+1);
  568.         strcpy(defnp->name,info);
  569.         defnp->uptodate  = FALSE;  /* actually  unknown  */
  570.         defnp->modified  = getmodified(defnp->name);
  571.         defnp->dependson = NULL;
  572.         defnp->howto  = NULL;
  573.         defnp->nextdefn  = NULL;
  574.  
  575.         /* now go through all of its  dependecies */
  576.         /* first move past the first  name */
  577.         pos = 0;
  578.         while (isspace(inline[pos]))
  579.           pos++;
  580.         while (!isspace(inline[pos])  &&  inline[pos]!='\0')
  581.           pos++;
  582.         /* now loop through those suckers */
  583.         doneline = FALSE;
  584.         while (!doneline)
  585.           {
  586.           while (isspace(inline[pos]))
  587.             pos++;
  588.           if (inline[pos] == '\0')
  589.             {
  590.             doneline =  TRUE;
  591.             continue;
  592.             }
  593.           for(i =  0; !isspace(inline[pos]) &&  inline[pos]!='\0'; )
  594.             info[i++] = inline[pos++];
  595.           info[i]  = '\0';
  596.           /* get a new struct  */
  597.           depp = (struct deprec *)get_mem(sizeof(struct deprec));
  598.           /* add it to the end of  deplist  */
  599.           if (defnp->dependson ==  NULL)
  600.             defnp->dependson =  depp;
  601.           else
  602.             {
  603.             depp2 =  defnp->dependson;
  604.             while (depp2->nextdep != NULL)
  605.               depp2 =  depp2->nextdep;
  606.             depp2->nextdep = depp;
  607.             }
  608.           depp->name = get_mem(strlen(info)+1);
  609.           strcpy(depp->name,info);
  610.           depp->nextdep =  NULL;
  611.           }
  612.         break ;
  613.       case '+': /* must be a continuation line */
  614.         uppercase(inline);
  615.  
  616.         /* now go through all of its  dependecies */
  617.         /* first move past the + sign */
  618.         pos = 1;
  619.         /* now loop through those suckers */
  620.         doneline = FALSE;
  621.         while (!doneline)
  622.           {
  623.           while (isspace(inline[pos]))
  624.             pos++;
  625.           if (inline[pos] == '\0')
  626.             {
  627.             doneline =  TRUE;
  628.             continue;
  629.             }
  630.           for(i =  0; !isspace(inline[pos]) &&  inline[pos]!='\0'; )
  631.             info[i++] = inline[pos++];
  632.           info[i]  = '\0';
  633.           /* get a new struct  */
  634.           depp = (struct deprec *)get_mem(sizeof(struct deprec));
  635.           /* add it to the end of  deplist  */
  636.           if (defnp->dependson ==  NULL)
  637.             defnp->dependson =  depp;
  638.           else
  639.             {
  640.             depp2 =  defnp->dependson;
  641.             while (depp2->nextdep != NULL)
  642.               depp2 =  depp2->nextdep;
  643.             depp2->nextdep = depp;
  644.             }
  645.           depp->name = get_mem(strlen(info)+1);
  646.           strcpy(depp->name,info);
  647.           depp->nextdep =  NULL;
  648.           }
  649.         break ;
  650.       case '$': /* must be a symbol definition */
  651.         /* now split  the line up into symbol and args */
  652.         for (pos=0;isspace(inline[pos]); pos++);
  653.           ;
  654.         for (i=pos; !isspace(inline[i])  && inline[i]!='\0'; i++)
  655.           ;
  656.         /* if there is something there,  allocate mem  and copy */
  657.         if (i != pos)
  658.           {
  659.           /* get a new struct  */
  660.           current->data = (struct sym_str *)get_mem(sizeof(struct sym_str));
  661.           current->next = (struct sym_ptr *)get_mem(sizeof(struct sym_ptr));
  662.           for(j=0; pos < i; )
  663.             current->data->symbol[j++] = inline[pos++] ;
  664.           current->data->symbol[j] = '\0';
  665.           /* now look  for  any  argumentative part */
  666.           while (isspace(inline[pos]))
  667.             pos++;
  668.           for(i=0; inline[pos] !=  '\0'; )
  669.             current->data->equals[i++] = inline[pos++] ;
  670.           current->data->equals[i] = '\0' ;
  671.           current = current->next ;
  672.           current->next = NULL ;
  673.           current->data = NULL ;
  674.           }
  675.         break ;
  676.       case '\t':
  677.         if (defnp ==  NULL)
  678.           {
  679.           fprintf(stderr,"Make: Howto  line without a definition\n");
  680.           fprintf(stderr,"Make: '%s'\n",inline);
  681.           }
  682.         /* now split  the line up into command and args */
  683.         for (pos=0;isspace(inline[pos]); pos++);
  684.           ;
  685.         for (i=pos; !isspace(inline[i])  && inline[i]!='\0'; i++)
  686.           ;
  687.         /* if there is something there,  allocate mem  and copy */
  688.         if (i != pos)
  689.           {
  690.           /* get a new struct  */
  691.           howp = (struct howrec *)get_mem(sizeof(struct howrec));
  692.           /* add it to the end of  howlist  */
  693.           if (defnp->howto ==  NULL)
  694.             defnp->howto = howp;
  695.           else
  696.             {
  697.             howp2 =  defnp->howto;
  698.             while (howp2->nexthow != NULL)
  699.               howp2 =  howp2->nexthow;
  700.             howp2->nexthow = howp;
  701.             }
  702.           /* copy  command  filename */
  703.           howp->howcom = get_mem(i-pos+1);
  704.           for(j=0; pos < i; )
  705.             howp->howcom[j++] = inline[pos++];
  706.           howp->howcom[j]  = '\0';
  707.           /* now look  for  any  argumentative part */
  708.           while (isspace(inline[pos]))
  709.             pos++;
  710.           howp->howargs =  get_mem(strlen(inline)-pos + 1);
  711.           for(i=0; inline[pos] !=  '\0'; )
  712.             howp->howargs[i++]  = inline[pos++];
  713.           howp->howargs[i] = '\0';
  714.           howp->nexthow =  NULL;
  715.           } /* if */
  716.         break ;
  717.       } /* switch */
  718.     } /* while */
  719.   fclose(  fil ) ;
  720. }  /* readmakefile */
  721.  
  722.  
  723. uppercase(s)
  724. char *s;
  725. {
  726.  
  727.   for( ;  *s != '\0'; s++)
  728.     *s = toupper(*s);
  729. }
  730.  
  731.  
  732. char *get_mem(size)    /* different name to differentiate it */
  733. int size;     /* from lattice C 2.11  function */
  734. {
  735.   char *p;
  736.  
  737.   if ((p  = getmem(size))  == NULL)  {
  738.     fprintf(stderr,"Make:  Ran out  of memory...\n");
  739.     exit(-1);
  740.   }
  741.   return(p);
  742. }
  743.  
  744.  
  745. long getmodified(name)
  746. char *name;
  747. {
  748.    struct  dt_tm {
  749.      int  time ;
  750.      int  date ;
  751.       } ;
  752.  
  753.    union vals {
  754.      long  ret_dt  ;
  755.      struct dt_tm  dt ;
  756.      } out_val ;
  757.  
  758.    union  REGS in_regs ;
  759.    union  REGS out_regs ;
  760.  
  761.    union FLAGS ret_flags ;
  762.    int file_handle ;
  763.  
  764.    /* get  the file handle  */
  765.    in_regs.x.dx =  (int)name ;
  766.    in_regs.h.al =  0 ;
  767.    in_regs.h.ah =  0x3d ;
  768.    ret_flags.all_flags = intdos( &in_regs, &out_regs )  ;
  769.    file_handle =  out_regs.x.ax ;
  770.    /* if  the file  doesn't  exist then return 0 for  date&time */
  771.    if ((ret_flags.flags.cf == 1) && ((file_handle == 2) ||
  772.                                (file_handle == 4) ||
  773.                                (file_handle == 5) ||
  774.                                (file_handle == 12)))
  775.      {
  776.      return( 0 )  ;
  777.      }
  778.  
  779.    /* get  the date */
  780.    in_regs.x.bx =  file_handle ;
  781.    in_regs.h.al =  0 ;
  782.    in_regs.h.ah =  0x57 ;
  783.    intdos( &in_regs, &out_regs )  ;
  784.    out_val.dt.date = out_regs.x.dx ;
  785.    out_val.dt.time = out_regs.x.cx ;
  786.  
  787.    /* close out the file  */
  788.    in_regs.x.bx =  file_handle ;
  789.    in_regs.h.ah =  0x3e ;
  790.    intdos( &in_regs, &out_regs )  ;
  791.    return( out_val.ret_dt  ) ;
  792.  
  793. }
  794.  
  795. long currtime()
  796. /* return a long encoding the current date and time */
  797. {
  798.    union  {
  799.      long  ret_dt  ;
  800.      int  dt[2] ;
  801.      } out_val ;
  802.  
  803.    union  REGS in_regs ;
  804.    union  REGS out_regs ;
  805.  
  806.    in_regs.h.al =  0 ;
  807.    in_regs.h.ah =  0x2a ;
  808.    intdos( &in_regs, &out_regs )  ;
  809.    out_regs.x.cx  -= 1980  ;
  810.  
  811.    out_val.dt[1]  = (out_regs.x.cx  << 9) ;
  812.    out_val.dt[1]  |= (out_regs.h.dh << 5)  ;
  813.    out_val.dt[1]  |= (out_regs.h.dl ) ;
  814.  
  815.    in_regs.h.al =  0 ;
  816.    in_regs.h.ah =  0x2c ;
  817.    intdos( &in_regs, &out_regs )  ;
  818.    out_val.dt[0]  = (out_regs.h.ch  << 11)  ;
  819.    out_val.dt[0]  |= (out_regs.h.cl << 5)  ;
  820.    out_val.dt[0]  |= (out_regs.h.dh >> 1)  ;
  821.    return( out_val.ret_dt  ) ;
  822.  
  823. }
  824.  
  825. long lmax(a,b)
  826. long a,b;
  827. {
  828.   return(a>b ? a  : b);
  829. }
  830. /* ---------- */
  831.